<template>
    <view v-if="showPopup" class="uni-popup" :class="[popupstyle, isDesktop ? 'fixforpc-z-index' : '']">
        <view @touchstart="touchstart">
            <uni-transition key="1" v-if="maskShow" name="mask" mode-class="fade" :styles="maskClass"
                :duration="duration" :show="showTrans" @click="onTap" />
            <uni-transition key="2" :mode-class="ani" name="content" :styles="transClass" :duration="duration"
                :show="showTrans" @click="onTap">
                <view class="uni-popup__wrapper" :style="getStyles" :class="[popupstyle]" @click="clear">
                    <slot />
                </view>
            </uni-transition>
        </view>
        <!-- #ifdef H5 -->
        <keypress v-if="maskShow" @esc="onTap" />
        <!-- #endif -->
    </view>
</template>

<script>
    // #ifdef H5
    import keypress from './keypress.js'
    // #endif

    /**
     * PopUp 弹出层
     * @description 弹出层组件，为了解决遮罩弹层的问题
     * @tutorial https://ext.dcloud.net.cn/plugin?id=329
     * @property {String} type = [top|center|bottom|left|right|message|dialog|share] 弹出方式
     * 	@value top 顶部弹出
     * 	@value center 中间弹出
     * 	@value bottom 底部弹出
     * 	@value left		左侧弹出
     * 	@value right  右侧弹出
     * 	@value message 消息提示
     * 	@value dialog 对话框
     * 	@value share 底部分享示例
     * @property {Boolean} animation = [true|false] 是否开启动画
     * @property {Boolean} maskClick = [true|false] 蒙版点击是否关闭弹窗(废弃)
     * @property {Boolean} isMaskClick = [true|false] 蒙版点击是否关闭弹窗
     * @property {String}  backgroundColor 主窗口背景色
     * @property {String}  maskBackgroundColor 蒙版颜色
     * @property {String}  borderRadius 设置圆角(左上、右上、右下和左下) 示例:"10px 10px 10px 10px"
     * @property {Boolean} safeArea		   是否适配底部安全区
     * @event {Function} change 打开关闭弹窗触发，e={show: false}
     * @event {Function} maskClick 点击遮罩触发
     */

    export default {
        name: 'uniPopup',
        components: {
            // #ifdef H5
            keypress
            // #endif
        },
        emits: ['change', 'maskClick'],
        props: {
            // 开启动画
            animation: {
                type: Boolean,
                default: true
            },
            // 弹出层类型，可选值，top: 顶部弹出层；bottom：底部弹出层；center：全屏弹出层
            // message: 消息提示 ; dialog : 对话框
            type: {
                type: String,
                default: 'center'
            },
            // maskClick
            isMaskClick: {
                type: Boolean,
                default: null
            },
            // TODO 2 个版本后废弃属性 ，使用 isMaskClick
            maskClick: {
                type: Boolean,
                default: null
            },
            backgroundColor: {
                type: String,
                default: 'none'
            },
            safeArea: {
                type: Boolean,
                default: true
            },
            maskBackgroundColor: {
                type: String,
                default: 'rgba(0, 0, 0, 0.4)'
            },
            borderRadius: {
                type: String,
            }
        },

        watch: {
            /**
             * 监听type类型
             */
            type: {
                handler: function(type) {
                    if (!this.config[type]) return
                    this[this.config[type]](true)
                },
                immediate: true
            },
            isDesktop: {
                handler: function(newVal) {
                    if (!this.config[newVal]) return
                    this[this.config[this.type]](true)
                },
                immediate: true
            },
            /**
             * 监听遮罩是否可点击
             * @param {Object} val
             */
            maskClick: {
                handler: function(val) {
                    this.mkclick = val
                },
                immediate: true
            },
            isMaskClick: {
                handler: function(val) {
                    this.mkclick = val
                },
                immediate: true
            },
            // H5 下禁止底部滚动
            showPopup(show) {
                // #ifdef H5
                // fix by mehaotian 处理 h5 滚动穿透的问题
                document.getElementsByTagName('body')[0].style.overflow = show ? 'hidden' : 'visible'
                // #endif
            }
        },
        data() {
            return {
                duration: 300,
                ani: [],
                showPopup: false,
                showTrans: false,
                popupWidth: 0,
                popupHeight: 0,
                config: {
                    top: 'top',
                    bottom: 'bottom',
                    center: 'center',
                    left: 'left',
                    right: 'right',
                    message: 'top',
                    dialog: 'center',
                    share: 'bottom'
                },
                maskClass: {
                    position: 'fixed',
                    bottom: 0,
                    top: 0,
                    left: 0,
                    right: 0,
                    backgroundColor: 'rgba(0, 0, 0, 0.4)'
                },
                transClass: {
                    backgroundColor: 'transparent',
                    borderRadius: this.borderRadius || "0",
                    position: 'fixed',
                    left: 0,
                    right: 0
                },
                maskShow: true,
                mkclick: true,
                popupstyle: 'top'
            }
        },
        computed: {
            getStyles() {
                let res = {
                    backgroundColor: this.bg
                };
                if (this.borderRadius || "0") {
                    res = Object.assign(res, {
                        borderRadius: this.borderRadius
                    })
                }
                return res;
            },
            isDesktop() {
                return this.popupWidth >= 500 && this.popupHeight >= 500
            },
            bg() {
                if (this.backgroundColor === '' || this.backgroundColor === 'none') {
                    return 'transparent'
                }
                return this.backgroundColor
            }
        },
        mounted() {
            const fixSize = () => {
                const {
                    windowWidth,
                    windowHeight,
                    windowTop,
                    safeArea,
                    screenHeight,
                    safeAreaInsets
                } = uni.getSystemInfoSync()
                this.popupWidth = windowWidth
                this.popupHeight = windowHeight + (windowTop || 0)
                // TODO fix by mehaotian 是否适配底部安全区 ,目前微信ios 、和 app ios 计算有差异，需要框架修复
                if (safeArea && this.safeArea) {
                    // #ifdef MP-WEIXIN
                    this.safeAreaInsets = screenHeight - safeArea.bottom
                    // #endif
                    // #ifndef MP-WEIXIN
                    this.safeAreaInsets = safeAreaInsets.bottom
                    // #endif
                } else {
                    this.safeAreaInsets = 0
                }
            }
            fixSize()
            // #ifdef H5
            // window.addEventListener('resize', fixSize)
            // this.$once('hook:beforeDestroy', () => {
            // 	window.removeEventListener('resize', fixSize)
            // })
            // #endif
        },
        // #ifndef VUE3
        // TODO vue2
        destroyed() {
            this.setH5Visible()
        },
        // #endif
        // #ifdef VUE3
        // TODO vue3
        unmounted() {
            this.setH5Visible()
        },
        // #endif
        activated() {
            this.setH5Visible(!this.showPopup);
        },
        deactivated() {
            this.setH5Visible(true);
        },
        created() {
            // this.mkclick =  this.isMaskClick || this.maskClick
            if (this.isMaskClick === null && this.maskClick === null) {
                this.mkclick = true
            } else {
                this.mkclick = this.isMaskClick !== null ? this.isMaskClick : this.maskClick
            }
            if (this.animation) {
                this.duration = 300
            } else {
                this.duration = 0
            }
            // TODO 处理 message 组件生命周期异常的问题
            this.messageChild = null
            // TODO 解决头条冒泡的问题
            this.clearPropagation = false
            this.maskClass.backgroundColor = this.maskBackgroundColor
        },
        methods: {
            setH5Visible(visible = true) {
                // #ifdef H5
                // fix by mehaotian 处理 h5 滚动穿透的问题
                document.getElementsByTagName('body')[0].style.overflow = visible ? "visible" : "hidden";
                // #endif
            },
            /**
             * 公用方法，不显示遮罩层
             */
            closeMask() {
                this.maskShow = false
            },
            /**
             * 公用方法，遮罩层禁止点击
             */
            disableMask() {
                this.mkclick = false
            },
            // TODO nvue 取消冒泡
            clear(e) {
                // #ifndef APP-NVUE
                e.stopPropagation()
                // #endif
                this.clearPropagation = true
            },

            open(direction) {
                // fix by mehaotian 处理快速打开关闭的情况
                if (this.showPopup) {
                    return
                }
                let innerType = ['top', 'center', 'bottom', 'left', 'right', 'message', 'dialog', 'share']
                if (!(direction && innerType.indexOf(direction) !== -1)) {
                    direction = this.type
                }
                if (!this.config[direction]) {
                    console.error('缺少类型：', direction)
                    return
                }
                this[this.config[direction]]()
                this.$emit('change', {
                    show: true,
                    type: direction
                })
            },
            close(type) {
                this.showTrans = false
                this.$emit('change', {
                    show: false,
                    type: this.type
                })
                clearTimeout(this.timer)
                // // 自定义关闭事件
                // this.customOpen && this.customClose()
                this.timer = setTimeout(() => {
                    this.showPopup = false
                }, 300)
            },
            // TODO 处理冒泡事件，头条的冒泡事件有问题 ，先这样兼容
            touchstart() {
                this.clearPropagation = false
            },

            onTap() {
                if (this.clearPropagation) {
                    // fix by mehaotian 兼容 nvue
                    this.clearPropagation = false
                    return
                }
                this.$emit('maskClick')
                if (!this.mkclick) return
                this.close()
            },
            /**
             * 顶部弹出样式处理
             */
            top(type) {
                this.popupstyle = this.isDesktop ? 'fixforpc-top' : 'top'
                this.ani = ['slide-top']
                this.transClass = {
                    position: 'fixed',
                    left: 0,
                    right: 0,
                    backgroundColor: this.bg,
                    borderRadius: this.borderRadius || "0"
                }
                // TODO 兼容 type 属性 ，后续会废弃
                if (type) return
                this.showPopup = true
                this.showTrans = true
                this.$nextTick(() => {
                    if (this.messageChild && this.type === 'message') {
                        this.messageChild.timerClose()
                    }
                })
            },
            /**
             * 底部弹出样式处理
             */
            bottom(type) {
                this.popupstyle = 'bottom'
                this.ani = ['slide-bottom']
                this.transClass = {
                    position: 'fixed',
                    left: 0,
                    right: 0,
                    bottom: 0,
                    //paddingBottom: this.safeAreaInsets + 'px',
                    backgroundColor: this.bg,
                    borderRadius: this.borderRadius || "0",
                }
                // TODO 兼容 type 属性 ，后续会废弃
                if (type) return
                this.showPopup = true
                this.showTrans = true
            },
            /**
             * 中间弹出样式处理
             */
            center(type) {
                this.popupstyle = 'center'
                //微信小程序下，组合动画会出现文字向上闪动问题，再此做特殊处理
                // #ifdef MP-WEIXIN
                this.ani = ['fade']
                // #endif
                // #ifndef MP-WEIXIN
                this.ani = ['zoom-out', 'fade']
                // #endif
                this.transClass = {
                    position: 'fixed',
                    /* #ifndef APP-NVUE */
                    display: 'flex',
                    flexDirection: 'column',
                    /* #endif */
                    bottom: 0,
                    left: 0,
                    right: 0,
                    top: 0,
                    justifyContent: 'center',
                    alignItems: 'center',
                    borderRadius: this.borderRadius || "0"
                }
                // TODO 兼容 type 属性 ，后续会废弃
                if (type) return
                this.showPopup = true
                this.showTrans = true
            },
            left(type) {
                this.popupstyle = 'left'
                this.ani = ['slide-left']
                this.transClass = {
                    position: 'fixed',
                    left: 0,
                    bottom: 0,
                    top: 0,
                    backgroundColor: this.bg,
                    borderRadius: this.borderRadius || "0",
                    /* #ifndef APP-NVUE */
                    display: 'flex',
                    flexDirection: 'column'
                    /* #endif */
                }
                // TODO 兼容 type 属性 ，后续会废弃
                if (type) return
                this.showPopup = true
                this.showTrans = true
            },
            right(type) {
                this.popupstyle = 'right'
                this.ani = ['slide-right']
                this.transClass = {
                    position: 'fixed',
                    bottom: 0,
                    right: 0,
                    top: 0,
                    backgroundColor: this.bg,
                    borderRadius: this.borderRadius || "0",
                    /* #ifndef APP-NVUE */
                    display: 'flex',
                    flexDirection: 'column'
                    /* #endif */
                }
                // TODO 兼容 type 属性 ，后续会废弃
                if (type) return
                this.showPopup = true
                this.showTrans = true
            }
        }
    }
</script>
<style lang="scss">
    .uni-popup {
        position: fixed;
        /* #ifndef APP-NVUE */
        z-index: 99;

        /* #endif */
        &.top,
        &.left,
        &.right {
            /* #ifdef H5 */
            top: var(--window-top);
            /* #endif */
            /* #ifndef H5 */
            top: 0;
            /* #endif */
        }

        .uni-popup__wrapper {
            /* #ifndef APP-NVUE */
            display: block;
            /* #endif */
            position: relative;

            /* iphonex 等安全区设置，底部安全区适配 */
            /* #ifndef APP-NVUE */
            // padding-bottom: constant(safe-area-inset-bottom);
            // padding-bottom: env(safe-area-inset-bottom);
            /* #endif */
            &.left,
            &.right {
                /* #ifdef H5 */
                padding-top: var(--window-top);
                /* #endif */
                /* #ifndef H5 */
                padding-top: 0;
                /* #endif */
                flex: 1;
            }
        }
    }

    .fixforpc-z-index {
        /* #ifndef APP-NVUE */
        z-index: 999;
        /* #endif */
    }

    .fixforpc-top {
        top: 0;
    }
</style>